(ns utilities.DBMain	
	(:gen-class)
	(:use utilities.readbinfile)
        (:import (java.io File RandomAccessFile))
        (:import (java.util.regex Pattern))
	(:use clojure.contrib.gen-html-docs))
	
(def archivoserver "tempserver.db")
(def archivoclient "tempclient.db")

(defn reading
	"Reads a record from the file. Returns an array where each
	  element is a record value."
	[recNo]
	(let [baseDatos  (read-bin-file archivoserver)
		records  (:records baseDatos) ]
		(get records recNo))) 
;---------------------------------------------------------------------------------------------------------------------
(defn pointer 
	"Moves pointer to the correct writing place."
	[recNo newfile fields-meta]
	(loop [_ nil
		numrec recNo]
		(if (= numrec 0)
			nil
			(if(= 0 (- (.getFilePointer newfile) (.length newfile)))
				nil
				(recur (read-one-record newfile fields-meta) (dec numrec))))))
;---------------------------------------------------------------------------------------------------------------------
(defn update-tuple
	"takes the given tuple and change it in the correct place"
	[recNo data]
	(with-open [file (RandomAccessFile. archivoclient "rw") ]
	(let [magic-number (.readInt file)
	      offset       (.readInt file)
	      num-fields   (.readShort file)
	      fields-meta  (read-fields-meta file num-fields)
	      moved_fields (pointer recNo file fields-meta)]
		(.writeShort file 00)
		(loop [
			xxx nil
			[[title length] & rests] fields-meta
			]
			(if title
			 	(if (contains? data (keyword title))
			 		(let [kee (keyword title)]
			 			(.write file (byte-array length (.getBytes (kee data)))))
			 	(recur  (read-str-len file length) rests))
			 nil)))))
;---------------------------------------------------------------------------------------------------------------------
(defn update
	"updates the values a record with the paraments sent in data"
	[recNo data]
	(loop [
		related-ks (keys data)
		xxx nil]
		(if (first related-ks)
			(recur (rest related-ks) (update-tuple recNo {(first related-ks) ((first related-ks) data)}))
		"updated done")))
;---------------------------------------------------------------------------------------------------------------------
(defn delete 
	"Erase a record from the file."
	[recNo]
	(with-open [newfile (RandomAccessFile. archivoclient "rw")]
		(let [_ (.readInt newfile)
		      _ (.readInt newfile)
		      num-fields (.readShort newfile)
		      fields-meta (read-fields-meta newfile num-fields)]
		      (pointer recNo newfile fields-meta)
		      (.writeShort newfile 0x8000))))
;---------------------------------------------------------------------------------------------------------------------
(defn writer
	"Writes into the file."
	[newfile fields-meta data]
	(.writeShort newfile 00)
		(loop [ _ nil
			[[title length] & rests] fields-meta
			]
			(if title
			 	(if (contains? data (keyword title))
			 		(let [kee (keyword title)]
			 			(recur (.write newfile (byte-array length (.getBytes (kee data)))) rests))
			 		(recur (.write newfile (byte-array length(.getBytes ""))) rests))
				nil)))
;---------------------------------------------------------------------------------------------------------------------
(defn read_all
	"Reads all the file"
	[newfile]
	(let [_ (.readInt newfile)
		_ (.readInt newfile)
		num-fields (.readShort newfile)
		fields-meta (read-fields-meta newfile num-fields)]
		(loop [_ nil
			recNo 0]
			(if(= 0 (- (.getFilePointer newfile) (.length newfile)))
				[recNo fields-meta]
				(recur (read-one-record newfile fields-meta) (inc recNo))))))
;-------------------------------------------------------------------------------
(defn place-tuple
	"returns a records with the fields in the correct place"
	[record]
	(loop
		[newRecord {:deleted "", :owner "", :date "", :rate "", :smoking "", :size "", :location "", :name ""}
		kees (keys newRecord) 
		res	{}]
		(if (first kees)
			(recur newRecord (rest kees) (conj res {(first kees) ((first kees)record)}))
res)))
	

(defn place-records
	"returns the records in the correct place"
	[records]
	(loop [newRecords []
		registers  records]
		(if (first registers)
			(recur (conj newRecords (place-tuple (first registers))) (rest registers))
newRecords)))

;---------------------------------------------------------------------------------------------------------------------		      	      	      

(defn create
	"Creates a new record"
	[data]
	(with-open [newfile (RandomAccessFile. archivoclient "rw")]
		(let [[newrecord fields-meta] (read_all newfile)]
			(writer newfile fields-meta data)
			newrecord)))
;---------------------------------------------------------------------------------------------------------------------		      	      	      
(defn takeoff-$
	"takes off the $ from rate in order to be compared"
	[register]
	(loop
		[keys-reg (keys register)
		 nuevo 	{}]
		(if (first keys-reg)
			 (if (= (first keys-reg) :rate)
			 	(if (> (.length ((first keys-reg) register)) 0)
			 		(if (.equals "$" (.substring ((first keys-reg) register) 0 1))
			 			(recur (rest keys-reg) (conj nuevo {(first keys-reg) 
							(.substring ((first keys-reg) register) 1 (.length ((first keys-reg) register)))})))
					(recur (rest keys-reg) (conj nuevo {(first keys-reg)((first keys-reg) register)})))
				 (recur (rest keys-reg) (conj nuevo {(first keys-reg)((first keys-reg) register)})))
			 nuevo)))
;---------------------------------------------------------------------------------------------------------------------
(defn add-extension
	"receives a map and adds the extension .* to the data related to the keys"
		[criteria]
		(loop
			[new-reg   (takeoff-$ criteria)
			keys-cri (keys new-reg)
			 nuevo 	{}]
			 (if (first keys-cri)
			 	 (recur new-reg (rest keys-cri) (conj nuevo {(first keys-cri) (str ((first keys-cri) new-reg)  ".*")}))
nuevo)))
;---------------------------------------------------------------------------------------------------------------------			
(defn matches 
	"returns a value depending if the criteria matches any of the 
	values in the register"
	[record criteria]
	(let [register (takeoff-$ record)
		ncriteria (add-extension criteria)
		]					
	(loop
		[nregister register
		ncriteria ncriteria
		keys-cri (keys ncriteria)]
		(if (first keys-cri)		
				(if (Pattern/matches ((first keys-cri) ncriteria)((first keys-cri) nregister))
					(recur nregister ncriteria (rest keys-cri))
				false)
true))))	
;---------------------------------------------------------------------------------------------------------------------
(defn place-tuple
	"returns a records with the fields in the correct place"
	[record]
	(loop
		[newRecord {:deleted "", :owner "", :date "", :rate "", :smoking "", :size "", :location "", :name ""}
		kees (keys newRecord) 
		res	{}]
		(if (first kees)
			(recur newRecord (rest kees) (conj res {(first kees) ((first kees)record)}))
res)))
;---------------------------------------------------------------------------------------------------------------------	
(defn place-records
	"returns the records in the correct place"
	[records]
	(loop [newRecords []
		registers  records]
		(if (first registers)
			(recur (conj newRecords (place-tuple (first registers))) (rest registers))
newRecords)))
;---------------------------------------------------------------------------------------------------------------------
(defn getrecords
	"Returns all the records."
	[]
	(let [database (read-bin-file archivoserver)
		records (:records database)]
(place-records records)))
;---------------------------------------------------------------------------------------------------------------------
(defn find-registers
	 "returns all the recordNumbers matching the criteria specified in the variable sent"
	 [criteria]
	 (let [records (getrecords)]
		 (loop [matchlist (list)
			  registers records 
			  n 0]
			  (if (first registers)
			 	  (if (matches (first registers) criteria)
			 	 	  (recur (cons n matchlist) (rest registers) (inc n))
			 	  (recur matchlist (rest registers) (inc n)))
			  (reverse matchlist)))))
;---------------------------------------------------------------------------------------------------------------------
(defn getrecordlist
	"returns a list ith the records contained in the recList"
	[recList]
	(loop [result []
		record recList]
		(if (first record)
			(recur (conj result (reading (first record))) (rest record))
(place-records result))))
;---------------------------------------------------------------------------------------------------------------------
(generate-documentation-to-file "./documentation.html" ['DBMain 'GUI 'DBMain-test 'servidor 'cliente 'prompt])
	
		
	
